#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 
# Author: Your Name
# Email: itdby@163.com
# Version: 1.1
# Date: 2024-05-30

import logging
import requests
import yaml
import time
from aliyunsdkcore.client import AcsClient
from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# 配置日志
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s',
                    handlers=[logging.FileHandler("ddns_update.log"),
                              logging.StreamHandler()])

# 加载配置
def load_config(config_file='config.yaml'):
    with open(config_file, 'r') as file:
        config = yaml.safe_load(file)
        validate_config(config)
        return config

def validate_config(config):
    required_keys = ['alibaba_cloud', 'domains', 'ip_providers']
    for key in required_keys:
        if key not in config:
            raise ValueError(f"Missing required config key: {key}")

    if not isinstance(config['domains'], list) or not config['domains']:
        raise ValueError("The 'domains' key must be a non-empty list.")

# 获取当前公网IP地址
def get_public_ip(providers):
    session = requests.Session()
    retry = Retry(connect=3, backoff_factor=0.5)
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)

    for provider in providers:
        try:
            response = session.get(provider, timeout=5)
            if response.status_code == 200:
                return response.text.strip()
        except requests.RequestException as e:
            logging.error(f"Error getting IP from {provider}: {e}")
    raise Exception("Unable to get public IP from any provider.")

# 更新阿里云DNS解析
def update_ddns(client, domain_name, record_id, rr, ip):
    request = UpdateDomainRecordRequest()
    request.set_RecordId(record_id)
    request.set_RR(rr)
    request.set_Type("A")
    request.set_Value(ip)

    try:
        response = client.do_action_with_exception(request)
        logging.info(f"Updated DDNS for {domain_name}: {response}")
    except Exception as e:
        logging.error(f"Failed to update DDNS for {domain_name}: {e}")
        raise

# 主函数
def main():
    config = load_config()
    alibaba_config = config['alibaba_cloud']
    domains_config = config['domains']
    ip_providers = config['ip_providers']

    client = AcsClient(alibaba_config['access_key_id'],
                       alibaba_config['access_key_secret'],
                       alibaba_config['region_id'])

    try:
        public_ip = get_public_ip(ip_providers)
        logging.info(f"Current public IP: {public_ip}")
        for domain in domains_config:
            update_ddns(client,
                        domain['domain_name'],
                        domain['record_id'],
                        domain['rr'],
                        public_ip)
    except Exception as e:
        logging.error(f"Error during DDNS update process: {e}")

if __name__ == "__main__":
    main()
